package zapx

import (
	"fmt"
	"os"
	"time"

	"fiberx/internal/global/configs"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

var L *zap.Logger

type Zapx struct{}

func New() *Zapx {
	return &Zapx{}
}
func (m *Zapx) Zapx(c *configs.Config) *zap.Logger {
	level := m.getZapLevel(c)
	var cores []zapcore.Core

	var weektime = func() string {
		start, end := GetCurrentWeek()
		return fmt.Sprintf("%s_%s", start.Format("2006-01-02"), end.Format("2006-01-02"))
	}()

	if _, err := os.Stat(c.Logger.Dir); os.IsNotExist(err) {
		err := os.MkdirAll(c.Logger.Dir, 0755)
		if err != nil {
			panic("无法创建日志目录: " + err.Error())
		}
	}

	// 配置 lumberjack 用于日志切割
	lumberjackLogger := &lumberjack.Logger{
		Filename:   c.Logger.Dir + c.Server.Name + "_" + weektime + ".log", // 生成带有日期的日志文件名
		MaxSize:    c.Logger.MaxAge,                                        // 每个日志文件的最大大小（MB）
		MaxBackups: c.Logger.MaxBackups,                                    // 保留的旧日志文件的最大数量
		MaxAge:     c.Logger.MaxAge,                                        // 保留旧日志文件的最大天数
		Compress:   c.Logger.Compress,                                      // 是否压缩旧日志文件
	}

	// 自定义时间编码器，时间精确到秒
	customTimeEncoder := func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString(t.Format("2006/01/02 15:04:05"))
	}

	// 配置日志的编码格式
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalColorLevelEncoder,
		EncodeTime:     customTimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}

	// 不同的编码器输出的格式就不同
	// 创建一个 JSON 编码器
	// jsonEncoder := zapcore.NewJSONEncoder(encoderConfig)
	// 创建一个控制台编码器
	consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)

	// 如果配置为输出到文件
	if c.Logger.OutputToFile {
		fileCore := zapcore.NewCore(consoleEncoder, zapcore.AddSync(lumberjackLogger), level)
		cores = append(cores, fileCore)
	}

	// 如果配置为输出到控制台
	if c.Logger.OutputToConsole {
		consoleCore := zapcore.NewCore(consoleEncoder, zapcore.AddSync(zapcore.Lock(os.Stdout)), level)
		cores = append(cores, consoleCore)
	}

	// 合并多个核心
	combinedCore := zapcore.NewTee(cores...)

	// 构建日志实例
	// log.Print("Initialization of zap successfully.")
	return zap.New(combinedCore, zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel))
}

// 将日志级别字符串转换为 zapcore.Level
func (m *Zapx) getZapLevel(c *configs.Config) zapcore.Level {
	switch c.Logger.Level {
	case "debug":
		return zapcore.DebugLevel
	case "info":
		return zapcore.InfoLevel
	case "warn":
		return zapcore.WarnLevel
	case "error":
		return zapcore.ErrorLevel
	case "dpanic":
		return zapcore.DPanicLevel
	case "panic":
		return zapcore.PanicLevel
	case "fatal":
		return zapcore.FatalLevel
	default:
		fmt.Printf("无效的日志级别: %s\n", c.Logger.Level)
		return zapcore.DebugLevel
	}
}

// GetCurrentWeek 获取当前周的日期范围
func GetCurrentWeek() (time.Time, time.Time) {
	now := time.Now()
	// 获取当前是周几，周日为 0，周一为 1，以此类推
	weekday := int(now.Weekday())
	if weekday == 0 {
		weekday = 7
	}
	// 计算周一的日期
	monday := now.AddDate(0, 0, -(weekday - 1))
	// 计算周日的日期
	sunday := now.AddDate(0, 0, 7-weekday)
	return monday, sunday
}

func init() {
	L = New().Zapx(configs.C)
}
